package com.yehebl.orm.check;

import java.io.File;
import java.lang.reflect.Field;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.*;

import com.yehebl.orm.anno.Column;
import com.yehebl.orm.anno.Entity;
import com.yehebl.orm.config.IConfig;
import com.yehebl.orm.data.connection.ConnectionManager;
import com.yehebl.orm.data.connection.LocalDataSource;
import com.yehebl.orm.data.connection.LocalJdbc;
import com.yehebl.orm.enums.DataType;
import com.yehebl.orm.manager.ScanManager;
import com.yehebl.orm.util.LogUtil;

public class DsCheckEntity {
	public static void start(IConfig config, String packageName, String url, String user, String password,String ...tableName) {
		if (config.getDataType().equals(DataType.MYSQL)) {
			config.setJdbcNoInit(new LocalJdbc(
					new LocalDataSource(new ConnectionManager(url, "com.mysql.jdbc.Driver", user, password))));
		}
		start(config,packageName,tableName);
	}

	public static void start(IConfig config, String packageName,String ...tableName) {
		String sourcePackage;
		LogUtil.printInfo("启动实体类生成程序...");
		String currentDir = System.getProperty("user.dir");
		sourcePackage = currentDir;
		LogUtil.printInfo("当前项目位置为：" + currentDir);
		File pomFile = new File(currentDir + File.separator + "pom.xml");
		if (pomFile.exists()) {
			sourcePackage = sourcePackage + File.separator + "src" + File.separator + "main" + File.separator + "java";
			LogUtil.printInfo("检测到maven项目源码路径为：" + sourcePackage);
		} else {
			sourcePackage = sourcePackage + File.separator + "src";
			LogUtil.printInfo("检测到项目源码路径为：" + sourcePackage);
		}
		LogUtil.printInfo("检测数据库实体类[" + packageName + "]下class");
		Set<Class<?>> classes = new LinkedHashSet<>(ScanManager.getClasses(packageName));
		String packageFlag = packageName.replaceAll("\\*", "");
		String packageDirName = packageFlag.replaceAll("\\.", "/");
		LogUtil.printInfo("如果检测到实体类不存在，则默认生成位置为：" + sourcePackage + File.separator + packageDirName);
		List<String> tableNameList;
		try {
			tableNameList = getTables(config.getJdbc().getConnection());
		} catch (SQLException e) {
			throw new RuntimeException(e);
		}
		for (String s : tableNameList) {
			if (tableName.length > 0) {
				boolean flag = false;
				for (String string : tableName) {
					if (s.equals(string)) {
						flag = true;
						break;
					}
				}
				if (!flag) {
					LogUtil.printInfo("不需要生成" + s + "的实体");
					continue;
				}
			}
			Class<?> existsClazz = null;
			for (Class<?> clazz : classes) {
				if ((config.classToTableRule(clazz).equals(s))) {
					existsClazz = clazz;
					break;
				}
			}
			String createTableDdl;
			try {
				createTableDdl = getCreateTable(config.getJdbc().getConnection(), s);
			} catch (SQLException e) {
				LogUtil.printWarn("获取表创建语句失败：" + e.getMessage());
				throw new RuntimeException(e);
			}

			if (existsClazz != null) {
				LogUtil.printInfo("表[" + s + "]已经存在于[" + existsClazz.getName() + "]需要比较字段");
				ClassAuto ca = EntityClass.generateEntityClass(createTableDdl);
				Entity entity = existsClazz.getAnnotation(Entity.class);
				if (entity == null) {
					LogUtil.printInfo(existsClazz.getName() + "该类不是实体类");
					LogUtil.printInfo("生成表[" + s + "]对应的实体类");
					EntityAuto.write(packageFlag, ca.getPackList(), ca.isTableId(), ca.getClassDesc(),
							s, ca.getFieldList(), sourcePackage + File.separator + packageDirName);
					return;
				}
				List<Field> fieldList = new ArrayList<>();
				getAllField(fieldList, existsClazz);

				for (FieldAuto fa : ca.getFieldList()) {
					int status = 0;// 数据字段不存在
					for (Field f : fieldList) {
						if (fa.getFieldName().equals(f.getName())) {
							status = 1;
							// 字段相同
							if (f.getAnnotation(Column.class) == null) {
								// 不是数据库表字段
								status = 2;
								LogUtil.printWarn(existsClazz.getName() + "." + f.getName() + "字段没有Column注解");
							} else if (!f.getType().getSimpleName().equals(fa.getType())) {
								// 类型与数据库不一致
								status = 3;
								LogUtil.printWarn(existsClazz.getName() + "." + f.getName() + "字段类型不一致,[表字段类型:"
										+ fa.getType() + "][实体字段类型:" + f.getType().getSimpleName() + "]");
							}
						}
					}
					if (status == 0) {
						LogUtil.printWarn(existsClazz.getName() + "." + fa.getFieldName() + "字段不存在");
					}

				}
			} else {
				LogUtil.printInfo("表[" + s + "]对应的实体类不存在");
				ClassAuto ca = EntityClass.generateEntityClass(createTableDdl);
				LogUtil.printInfo("生成表[" + s + "]对应的实体类");
				EntityAuto.write(packageFlag, ca.getPackList(), ca.isTableId(), ca.getClassDesc(), s,
						ca.getFieldList(), sourcePackage + File.separator + packageDirName);
			}
		}

	}

	private static String getCreateTable(Connection conn, String tableName) throws SQLException {
		Statement createStatement = conn.createStatement();
		ResultSet rs = createStatement.executeQuery("show create table " + tableName);
		String createSql = null;
		while (rs.next()) {
			createSql = rs.getString(2);
		}
		rs.close();
		conn.close();
		return createSql;
	}

	private static List<String> getTables(Connection conn) throws SQLException {
		List<String> tableNameList = new ArrayList<>();
		DatabaseMetaData dbMetData = conn.getMetaData();
		ResultSet rs = dbMetData.getTables(null, null, null, new String[] { "TABLE", "VIEW" });
		while (rs.next()) {
			if (rs.getString(4) != null
					&& (rs.getString(4).equalsIgnoreCase("TABLE") || rs.getString(4).equalsIgnoreCase("VIEW"))) {
				String tableName = rs.getString(3).toLowerCase();
				tableNameList.add(tableName);
			}
		}
		rs.close();
		conn.close();
		return tableNameList;
	}

	private static List<Field> getAllField(List<Field> list, Class<?> clazz) {
		Field[] declaredFields = clazz.getDeclaredFields();
		Collections.addAll(list, declaredFields);
		Class<?> parentClazz = clazz.getSuperclass();
		if (parentClazz == null) {
			return list;
		}
		return getAllField(list, parentClazz);
	}
}
